package com.gosling.cloudspace.tools;

import org.apache.commons.math3.linear.*;

public class HillCipher {
    private RealMatrix keyMatrix;

    public HillCipher(double[][] key) {
        this.keyMatrix = new Array2DRowRealMatrix(key);
    }

    public String encrypt(String plaintext) {
        int n = keyMatrix.getColumnDimension();
        int padding = n - (plaintext.length() % n);
        if (padding < n) {
            plaintext = String.format("%-" + (plaintext.length() + padding) + "s", plaintext);
        }
        StringBuilder ciphertext = new StringBuilder();
        for (int i = 0; i < plaintext.length(); i += n) {
            RealVector vec = new ArrayRealVector(n);
            for (int j = 0; j < n; j++) {
                vec.setEntry(j, plaintext.charAt(i + j) - 'a');
            }
            RealVector result = keyMatrix.operate(vec);
            for (int j = 0; j < n; j++) {
                int value = (int) (result.getEntry(j) + 0.5) % 26;
                ciphertext.append((char) (value + 'a'));
            }
        }
        return ciphertext.toString();
    }

    public String decrypt(String ciphertext) {
        RealMatrix inverseKey = new LUDecomposition(keyMatrix).getSolver().getInverse();
        int n = keyMatrix.getColumnDimension();
        StringBuilder plaintext = new StringBuilder();
        for (int i = 0; i < ciphertext.length(); i += n) {
            RealVector vec = new ArrayRealVector(n);
            for (int j = 0; j < n; j++) {
                vec.setEntry(j, ciphertext.charAt(i + j) - 'a');
            }
            RealVector result = inverseKey.operate(vec);
            for (int j = 0; j < n; j++) {
                int value = ((int) (result.getEntry(j) + 0.5) % 26 + 26) % 26; // handle negative values
                plaintext.append((char) (value + 'a'));
            }
        }
        return plaintext.toString();
    }

    public static void main(String[] args) {
        double[][] key = {{3, 3}, {2, 5}}; // 2x2 key matrix
        HillCipher cipher = new HillCipher(key);
        String plaintext = "hello";
        String ciphertext = cipher.encrypt(plaintext);
        String decryptedtext = cipher.decrypt(ciphertext);
        System.out.println("Plaintext: " + plaintext);
        System.out.println("Ciphertext: " + ciphertext);
        System.out.println("Decrypted text: " + decryptedtext);
    }
}
